//#include "StdAfx.h"
#include "inifile.h"
#include "share_memory.h"
#include "gpio1500a.h"
#include <fstream>
#include <iostream>
#include <pthread.h>
#include <stdio.h>
#include <string>
#include <string.h>
#include <stdlib.h>
#include <list>
#include <sys/ipc.h>   
#include <sys/shm.h>
#include <sys/types.h> 
#include <fcntl.h>
#include <sys/time.h>
#include <chrono>
#include <dirent.h>
#include <unistd.h>
#include "i2c_ctrl.h"

//#define INIDEBUG
#define FILENAME "/etc/brightness.conf" // 指定文件名
extern Gpio_1500a *gpio;

IniFile::IniFile()
{
	for(int i=0; i<6; i++){
		key_counts[i] = 0;
	}

	if (0 != access(FILENAME, 0))
	{
		printf("%s not exits, now create it!\n", FILENAME);
		ofstream OpenFile(FILENAME);
		if (OpenFile.fail())
		{
			printf("error, %s create failed!", FILENAME);
		}else{
			OpenFile << "[brightness]" << endl;
			// OpenFile << "current=255" << endl;
			OpenFile << "min=10" << endl;
			OpenFile << "max=255" << endl;
			OpenFile.close();
		}
	}

	// SetValue("brightness", "current", "255");
	SetValue("brightness", "min", "10");
	SetValue("brightness", "max", "255");
	ReadINI(FILENAME);

	// curBrightness = stoi(GetValue("brightness", "current"));
	maxBrightness = stoi(GetValue("brightness", "max"));
	minBrightness = stoi(GetValue("brightness", "min"));
	brightnessIndexInit();
}

void IniFile::initLater(){
	// 创建共享内存
	shareMemory = new CShareMemory("bl_ctrl", BL_SHM_ID, BL_BUF_SIZE);
	curBrightness = ReadBrightness();
	SetBrightness(curBrightness);
	i2c_write_byte_one(0x12, 0xad, 0x01);		// 设置频率为27K
	i2c_write_byte_one(0x12, 0xa5, 0xa0);		// 设置为内部PWM
	// i2c_write_byte_one(0x12, 0xa5, 0x80);	// 设置为外部PWM

	// cout << "stepValue: " << stepValue << endl;
	// 打开背光
	SwitchLightON(true);
}

void IniFile::brightnessIndexInit(){
	if (maxBrightness > 255)
		maxBrightness = 255;
	if (minBrightness < 0)
		minBrightness = 0;
	if (minBrightness > 90)
		minBrightness = 90;
	if (maxBrightness < minBrightness + 20)
		maxBrightness = minBrightness + 20;
	if (curBrightness > maxBrightness)
		curBrightness = maxBrightness;
	if (curBrightness < minBrightness)
		curBrightness = minBrightness;
}

void IniFile::SetBrightness(int cur)
{
	curBrightness = cur;

	unsigned char cur_byte = cur;

	// gpio->Read_status((unsigned char)0xa2, (unsigned char)(cur*0.39));  		// 外部PWM控制
	i2c_write_byte_one(0x12, 0xa7, cur_byte);						// 内部PWM控制
	shareMemory->PutToShareMem((const u8 *)&cur, 0, 4);
}

/* 设置按键的计数增加 */
void IniFile::IncKeyCounts(int key_types)
{
	unsigned int key_values;
	switch (key_types)
	{
	case POWEROFF_KEY:
		key_counts[0]++;
		key_values = key_counts[0];
		shareMemory->PutToShareMem((const u8 *)&key_values, 8, 4);
		break;
	case LIGHT_UP:
		key_counts[1]++;
		key_values = key_counts[1];
		shareMemory->PutToShareMem((const u8 *)&key_values, 12, 4);
		break;
	case LIGHT_DOWN:
		key_counts[2]++;
		key_values = key_counts[2];
		shareMemory->PutToShareMem((const u8 *)&key_values, 16, 4);
		break;
	case VOLUME_UP:
		key_counts[3]++;
		key_values = key_counts[3];
		shareMemory->PutToShareMem((const u8 *)&key_values, 20, 4);
		break;
	case VOLUME_DOWN:
		key_counts[4]++;
		key_values = key_counts[4];
		shareMemory->PutToShareMem((const u8 *)&key_values, 24, 4);
		break;
	case PANEL_SWITCH:
		key_counts[5]++;
		key_values = key_counts[5];
		shareMemory->PutToShareMem((const u8 *)&key_values, 28, 4);
		break;
	default:
		break;
	}
}

void IniFile::SwitchLightON(bool isOn)
{
	if(isOn)
		gpio->Read_status((unsigned char)0xa1, (unsigned char)0xaa);
	else
	{
		gpio->Read_status((unsigned char)0xa1, (unsigned char)0xbb);
	}
	
}

#define DP_EN_FILE_1 "/sys/class/drm/card0-eDP-1/enabled"
#define DP_EN_FILE_2 "/sys/class/drm/card0-DP-1/enabled"
#define DP_EN_FILE_3 "/sys/class/drm/card0-DP-2/enabled"
bool IniFile::LvdsIsEnabled(){
	static int dp_cannel = 0;
	string str_line = "";
	int ret = 0;
	int userSet;
	
	// 通过共享内存获取亮度设置值
	shareMemory->GetFromShareMem((u8 *)&userSet, 0, 4);
	if(((int)curBrightness) != userSet){
		curBrightness = userSet;
		cout << "用户程序设置亮度为: " << userSet << endl;
		SetBrightness(curBrightness);
	}

	// 获取dp_lvds 通道的使能状态
	if(dp_cannel <= 1){
		ifstream in_conf_file_1(DP_EN_FILE_1);
		if (getline(in_conf_file_1, str_line))
		{
			if(0 == str_line.compare("enabled")){
				ret = 1;
				dp_cannel = 1;
			}
		}
		in_conf_file_1.close();
	}
	
	if(2 == dp_cannel || (0 == dp_cannel && 0 == access(DP_EN_FILE_2, 0))){
		ifstream in_conf_file_2(DP_EN_FILE_2);
		if (getline(in_conf_file_2, str_line))
		{
			if(0 == str_line.compare("enabled")){
				ret = 1;
				dp_cannel = 2;
			}
		}
		in_conf_file_2.close();
	}

	if(3 == dp_cannel || (0 == dp_cannel && 0 == access(DP_EN_FILE_3, 0))){
		ifstream in_conf_file_3(DP_EN_FILE_3);
		if (getline(in_conf_file_3, str_line))
		{
			if(0 == str_line.compare("enabled")){
				ret = 1;
				dp_cannel = 3;
			}
		}
		in_conf_file_3.close();
	}

	if(0 == ret)
		return false;
	else
	{
		return true;
	}
	
}

bool IniFile::SetBrightnessUP()
{
	/*
	if (curBrightness < maxBrightness){
		curBrightness += stepValue;
		if (curBrightness > maxBrightness)
		{
			curBrightness = maxBrightness;
		}
		SetBrightness(curBrightness);
		return true;
	}else{
		return false;
	}
	*/
	return true;
}
bool IniFile::SetBrightnessDown()
{
	/*
	if (curBrightness > minBrightness){
		curBrightness -= stepValue;
		if (curBrightness < minBrightness)
		{
			curBrightness = minBrightness;
		}
		SetBrightness(curBrightness);
		return true;
	}else{
		return false;
	}
	*/
	return true;
}

IniFile::~IniFile()
{
	//close(config_fd);
}

//************************************************************************
// 函数名称:    	TrimString
// 访问权限:    	public
// 创建日期:		2017/01/05
// 创 建 人:
// 函数说明:		去除空格
// 函数参数: 	string & str	输入的字符串
// 返 回 值:   	std::string &	结果字符串
//************************************************************************
string &TrimString(string &str)
{
	string::size_type pos = 0;
	while (str.npos != (pos = str.find(" ")))
		str = str.replace(pos, pos + 1, "");
	return str;
}

//************************************************************************
// 函数名称:    	ReadINI
// 访问权限:    	public
// 创建日期:		2017/01/05
// 创 建 人:
// 函数说明:		读取INI文件，并将其保存到map结构中
// 函数参数: 	string path	INI文件的路径
// 返 回 值:   	int
//************************************************************************
int IniFile::ReadINI(string path)
{
	ifstream in_conf_file(path.c_str());
	if (!in_conf_file)
	{
		return -1;
	}

	string str_line = "";
	string str_root = "";
	vector<ININode> vec_ini;
	while (getline(in_conf_file, str_line))
	{
		string::size_type left_pos = 0;
		string::size_type right_pos = 0;
		string::size_type equal_div_pos = 0;
		string str_key = "";
		string str_value = "";
		if ((str_line.npos != (left_pos = str_line.find("["))) && (str_line.npos != (right_pos = str_line.find("]"))))
		{
			//cout << str_line.substr(left_pos+1, right_pos-1) << endl;
			str_root = str_line.substr(left_pos + 1, right_pos - 1);
		}

		if (str_line.npos != (equal_div_pos = str_line.find("=")))
		{
			str_key = str_line.substr(0, equal_div_pos);
			str_value = str_line.substr(equal_div_pos + 1, str_line.size() - 1);
			str_key = TrimString(str_key);
			str_value = TrimString(str_value);
			//cout << str_key << "=" << str_value << endl;
		}

		if ((!str_root.empty()) && (!str_key.empty()) && (!str_value.empty()))
		{
			ININode ini_node(str_root, str_key, str_value);
			vec_ini.push_back(ini_node);
			//cout << vec_ini.size() << endl;
		}
	}
	in_conf_file.close();
	in_conf_file.clear();

	//vector convert to map
	map<string, string> map_tmp;
	for (vector<ININode>::iterator itr = vec_ini.begin(); itr != vec_ini.end(); ++itr)
	{
		map_tmp.insert(pair<string, string>(itr->root, ""));
	} //提取出根节点
	for (map<string, string>::iterator itr = map_tmp.begin(); itr != map_tmp.end(); ++itr)
	{
#ifdef INIDEBUG
		cout << "根节点： " << itr->first << endl;
#endif //INIDEBUG
		//SubNode sn;
		for (vector<ININode>::iterator sub_itr = vec_ini.begin(); sub_itr != vec_ini.end(); ++sub_itr)
		{
			if (sub_itr->root == itr->first)
			{
#ifdef INIDEBUG
				cout << "键值对： " << sub_itr->key << "=" << sub_itr->value << endl;
#endif //INIDEBUG
				//sn.InsertElement(sub_itr->key, sub_itr->value);
				SetValue(sub_itr->root, sub_itr->key, sub_itr->value);
			}
		}
		//map_ini.insert(pair<string, SubNode>(itr->first, sn));
	}
	return 1;
}

//************************************************************************
// 函数名称:    	GetValue
// 访问权限:    	public
// 创建日期:		2017/01/05
// 创 建 人:
// 函数说明:		根据给出的根结点和键值查找配置项的值
// 函数参数: 	string root		配置项的根结点
// 函数参数: 	string key		配置项的键
// 返 回 值:   	std::string		配置项的值
//************************************************************************
string IniFile::GetValue(string root, string key)
{
	map<string, SubNode>::iterator itr = map_ini.find(root);
	map<string, string>::iterator sub_itr = itr->second.sub_node.find(key);
	if (!(sub_itr->second).empty())
		return sub_itr->second;
	return "";
}

//************************************************************************
// 函数名称:    	WriteINI
// 访问权限:    	public
// 创建日期:		2017/01/05
// 创 建 人:
// 函数说明:		保存XML的信息到文件中
// 函数参数: 	string path	INI文件的保存路径
// 返 回 值:   	int
//************************************************************************
int IniFile::WriteINI()
{
	int max, min;
	char buf[20];
	ReadINI(FILENAME);
	max = stoi(GetValue("brightness", "max"));
	min = stoi(GetValue("brightness", "min"));

	if(max != (int)maxBrightness || min != (int)minBrightness){
		printf("Brightness max %d->%d\n", (int)maxBrightness, max);
		printf("Brightness min %d->%d\n", (int)minBrightness, min);
		minBrightness = min;
		maxBrightness = max;
		brightnessIndexInit();
	
		sprintf(buf, "%d", (int)maxBrightness);
		SetValue("brightness", "max", buf);
		sprintf(buf, "%d", (int)minBrightness);
		SetValue("brightness", "min", buf);
	}
	// sprintf(buf, "%d", (int)curBrightness);
	// SetValue("brightness", "current", buf);

	string path = FILENAME;
	ofstream out_conf_file(path.c_str());
	if (!out_conf_file)
		return -1;

	for (map<string, SubNode>::iterator itr = map_ini.begin(); itr != map_ini.end(); ++itr)
	{
		out_conf_file << "[" << itr->first << "]" << endl;
		for (map<string, string>::iterator sub_itr = itr->second.sub_node.begin(); sub_itr != itr->second.sub_node.end(); ++sub_itr)
		{
			out_conf_file << sub_itr->first << "=" << sub_itr->second << endl;
		}
	}

	out_conf_file.close();
	out_conf_file.clear();

	return 1;
}

//************************************************************************
// 函数名称:    	SetValue
// 访问权限:    	public
// 创建日期:		2017/01/05
// 创 建 人:
// 函数说明:		设置配置项的值
// 函数参数: 	string root		配置项的根节点
// 函数参数: 	string key		配置项的键
// 函数参数: 	string value	配置项的值
// 返 回 值:   	std::vector<ININode>::size_type
//************************************************************************
vector<ININode>::size_type IniFile::SetValue(string root, string key, string value)
{
	map<string, SubNode>::iterator itr = map_ini.find(root); //查找
	if (map_ini.end() != itr)
	{
		//itr->second.sub_node.insert(pair<string, string>(key, value));
		itr->second.sub_node[key] = value;
	} //根节点已经存在了，更新值
	else
	{
		SubNode sn;
		sn.InsertElement(key, value);
		map_ini.insert(pair<string, SubNode>(root, sn));
	} //根节点不存在，添加值

	return map_ini.size();
}

int IniFile::ReadBrightness()
{
	static int bg_old = -1;
	string in_conf_file = "/sys/class/drm/card0-eDP-1/radeon_bl0/brightness";
	int ret = 255;
	int bgvalue = 255;

	std::fstream bgfile(in_conf_file);
	bgfile >> bgvalue;					// 从is流中读入一个int整数存入i中
	
	if(bgvalue < 24){					// 系统在亮度<=24时，认为亮度为0
		bgvalue = 24;
		bgfile << 24;
	}				
	bgfile.close();	
		
	// 计算实际值 bgvalue:0~255  bgvalue/255.0:0~1.0
	ret = minBrightness + (int)( (bgvalue-24)/231.0*(maxBrightness - minBrightness) );

	// if(ret > 255)
	// 	ret = 255;

	if(bg_old != bgvalue){
		cout << "bg: " << bgvalue << "->" << ret << endl;
		bg_old = bgvalue;
	}
	
	return ret;
}

//************************************************************************
// 函数名称:    	Travel
// 访问权限:    	public
// 创建日期:		2017/01/05
// 创 建 人:
// 函数说明:		遍历打印INI文件
// 返 回 值:   	void
//************************************************************************
void IniFile::Travel()
{
	for (map<string, SubNode>::iterator itr = this->map_ini.begin(); itr != this->map_ini.end(); ++itr)
	{
		cout << "[" << itr->first << "]" << endl;
		for (map<string, string>::iterator itr1 = itr->second.sub_node.begin(); itr1 != itr->second.sub_node.end();
			 ++itr1)
		{
			cout << "    " << itr1->first << " = " << itr1->second << endl;
		}
	}
	// SetBrightness(curBrightness);
}
